#pragma once

extern Mutex m_mpqMutex; // we should not read asynchron as Stormlib is based on procedures!

class CMpqFile
{
	ui8* m_buffer;
	ui32 m_fileSize;
	ui32 m_incpoint;
	bool m_found;
public:
	CMpqFile(std::string szFile)
	{
		m_mpqMutex.Acquire();
		m_buffer = 0;
		FILE* pFile;
		HANDLE hFile = sMpqHandler.GetFile(szFile, &pFile);
		if(hFile == INVALID_HANDLE_VALUE)
		{
			m_mpqMutex.Release();
			m_found = false;
			return;
		}
		if(hFile == MPQ_FILE_HANDLE)
		{
			fseek(pFile, 0, SEEK_END);
			m_fileSize = ftell(pFile);
			fseek(pFile, 0, SEEK_SET);
			m_buffer = new ui8[m_fileSize];
			fread(m_buffer, m_fileSize, 1, pFile);
			m_found = true;
			m_incpoint = 0;
			fclose(pFile);
		}
		else
		{
			m_fileSize = SFileGetFileSize(hFile);
			SFileSetFilePointer(hFile, 0, 0, FILE_BEGIN);
			m_buffer = new ui8[m_fileSize];
			SFileReadFile(hFile, m_buffer, m_fileSize);
			SFileCloseFile(hFile);
			m_found = true;
			m_incpoint = 0;
		}
		m_mpqMutex.Release();
	}

	CMpqFile(HANDLE hFile, bool dummy)
	{
		m_mpqMutex.Acquire();
		m_buffer = 0;
		if(hFile == INVALID_HANDLE_VALUE)
		{
			m_mpqMutex.Release();
			m_found = false;
			return;
		}
		m_fileSize = SFileGetFileSize(hFile);
		SFileSetFilePointer(hFile, 0, 0, FILE_BEGIN);
		m_buffer = new ui8[m_fileSize];
		SFileReadFile(hFile, m_buffer, m_fileSize);
		SFileCloseFile(hFile);
		m_found = true;
		m_incpoint = 0;
		m_mpqMutex.Release();
	}

	~CMpqFile()
	{
		if(m_found && m_buffer)
			delete [] m_buffer;
	}

	inline bool IsOpened() { return m_found; }
	inline ui8* GetCurPointer() { return m_buffer + m_incpoint; }
	inline ui8* GetPointer() { return m_buffer; }
	inline void SetInc(ui32 inc) { m_incpoint = inc; }
	inline void ModInc(i32 inc) { m_incpoint += inc; }
	inline ui32 TellInc() { return m_incpoint; }
	inline ui32 GetSize() { return m_fileSize; }
	inline void Read(ui32 pos, ui32 len, void* pOut)
	{
		if(pos + len > m_fileSize)
			return;
		memcpy(pOut, m_buffer + pos, len);
	}

	inline void ReadInc(ui32 len, void* pOut)
	{
		if(m_incpoint + len > m_fileSize)
			return;
		Read(m_incpoint, len, pOut);
		m_incpoint += len;
	}

	template<typename T>
	T Read(ui32 pos) {
		T ret;
		Read(pos, sizeof(T), &ret);
		return ret;
	}

	template<typename T>
	T ReadInc() {
		T ret;
		ReadInc(sizeof(T), &ret);
		return ret;
	}
};